#include "WmarkBufManager.h"

namespace camera
{
    namespace algorithm
    {

        WmarkBufManager::WmarkBufManager()
        {
            mWmarkDev = WmarkDev::getInstance();
        }

        WmarkBufManager::~WmarkBufManager()
        {
            delWmarkBufs();
        }

        int WmarkBufManager::initWmarkBuf()
        {
            int ret = -1;
            int i = -1;
            uint64_t bufLen;
            uint32_t bufNum;

            if (isInitWmarkBufs())
            {
                return 0;
            }

            if (!mWmarkDev)
            {
                ALOGE("%s %d error", __func__, __LINE__);
                return -1;
            }

            ret = mWmarkDev->getWmarkBufsInfo(bufNum, bufLen);
            if (ret)
            {
                ALOGE("%s %d error", __func__, __LINE__);
                return -1;
            }

            ALOGD("get wmarkbufs num=%d len=%llu", bufNum, (unsigned long long)bufLen);

            mWmarkBufsMutex.lock();

            mWmarkBufsArray = (WmarkBuf *)malloc(bufNum * sizeof(WmarkBuf));
            if (!mWmarkBufsArray)
            {
                ALOGE("%s %d malloc fail", __func__, __LINE__);
                mWmarkBufsMutex.unlock();
                return -1;
            }

            for (i = 0; i < bufNum; i++)
            {
                mWmarkBufsArray[i].buf = (uint8_t *)malloc(bufLen * sizeof(uint8_t));
                if (!mWmarkBufsArray[i].buf)
                {
                    mWmarkBufsArrayNum = i;
                    ALOGE("%s %d malloc fail", __func__, __LINE__);
                    mWmarkBufsMutex.unlock();
                    return -1;
                }
                mWmarkBufsArray[i].bufMaxLen = bufLen;
            }

            mWmarkBufsArrayNum = i;

            mWmarkDev->start();

            mWmarkBufsMutex.unlock();
            return ret;
        }

        bool WmarkBufManager::isInitWmarkBufs()
        {
            bool ret = false;

            mWmarkBufsMutex.lock();

            if (!mWmarkBufsArray || mWmarkBufsArrayNum <= 0)
            {
                ret = false;
            }
            else
            {
                ret = true;
            }

            mWmarkBufsMutex.unlock();

            return ret;
        }

        WmarkBuf *WmarkBufManager::getIndexWmarkBuf(int index)
        {
            WmarkBuf *ret = NULL;

            while (!isInitWmarkBufs())
            {
                initWmarkBuf();
            }

            mWmarkBufsMutex.lock();

            if (index >= mWmarkBufsArrayNum || index < 0)
            {
                ALOGE("%s %d index error", __func__, __LINE__);
                mWmarkBufsMutex.unlock();
                return NULL;
            }

            ret = &mWmarkBufsArray[index];
            mWmarkBufsMutex.unlock();

            ALOGD("mWmarkBufsArray[%d] = %p", index, ret);
            return ret;
        }

        int WmarkBufManager::delWmarkBufs()
        {
            if (!isInitWmarkBufs())
            {
                return 0;
            }

            mWmarkBufsMutex.lock();
            for (size_t i = 0; i < mWmarkBufsArrayNum; i++)
            {
                if (mWmarkBufsArray[i].buf)
                {
                    free(mWmarkBufsArray[i].buf);
                    mWmarkBufsArray[i].buf = NULL;
                }
            }

            free(mWmarkBufsArray);
            mWmarkBufsArray = NULL;
            mWmarkBufsArrayNum = -1;
            mWmarkBufsMutex.unlock();

            return 0;
        }

        int WmarkBufManager::hanlePngOverlay(algorithm_info_t &_hal)
        {
            if (!isInitWmarkBufs())
            {
                ALOGE("%s %d : no init", __func__, __LINE__);
                initWmarkBuf();
                return -1;
            }
            ALOGV("%s ->", __func__);
            mWmarkBufsMutex.lock();

            for (size_t i = 0; i < mWmarkBufsArrayNum; i++)
            {
                if (isEnableWmark(_hal.device_path_, mWmarkBufsArray[i]))
                {
                    switch (mWmarkBufsArray[i].property.info.picture.type)
                    {
                    case TYPE_STR:
                        handleStr(_hal, mWmarkBufsArray[i]);
                        break;
                    case TYPE_PNG:
                        handlePng(_hal, mWmarkBufsArray[i]);
                        break;
                    default:
                        ALOGW("%s %d error", __func__, __LINE__);
                        break;
                    }
                }
            }

            mWmarkBufsMutex.unlock();
            return 0;
        }

        bool WmarkBufManager::isEnableWmark(string halCameraId, WmarkBuf &wmarBufInfo)
        {
            int appCameraId = -1;
            int _halCameraId;
            int _appCameraId = -1;
            uint8_t *faceid = NULL;
            int count = -1;

            if (0 == wmarBufInfo.property.info.picture.display.en)
            {
                return false;
            }

            sscanf(halCameraId.c_str(), "/dev/video%d", &_halCameraId);

            count = sizeof(wmarBufInfo.property.info.picture.display.face_id) / sizeof(uint8_t);
            faceid = (uint8_t *)&wmarBufInfo.property.info.picture.display.face_id;
            for (size_t i = 0; i < count; i++)
            {
                appCameraId = faceid[i];
                _appCameraId = appCameraId + 51 - 2;
                ALOGV("halCameraId=%d _appCameraId=%d = 51 -2 + appCameraId(%d)", _halCameraId, _appCameraId, appCameraId);
                if (_appCameraId == _halCameraId)
                {
                    return true;
                }
            }

            return false;
        }

        int WmarkBufManager::handleStr(algorithm_info_t &info, WmarkBuf &wmarBufInfo)
        {
            unsigned char *bufptr = info.bufptr;
            int size = info.size;
            int rawWidth = info.rawWidth;
            int rawHeight = info.rawHeight;
            int channel = size / (rawWidth * rawHeight);

            int displayX = -1, displayY = -1;
            int watermark_h = -1, watermark_w = -1, wmatermark_channel = -1;
            uint8_t *buf = wmarBufInfo.buf;

            if (!buf || wmarBufInfo.property.info.picture.display.len > wmarBufInfo.bufMaxLen)
            {
                ALOGE("%s %d : error", __func__, __LINE__);
                return -1;
            }

            displayX = wmarBufInfo.property.info.picture.display.x;
            displayY = wmarBufInfo.property.info.picture.display.y;
            watermark_w = wmarBufInfo.property.info.picture.display.w;
            watermark_h = wmarBufInfo.property.info.picture.display.h;
            wmatermark_channel = wmarBufInfo.property.info.picture.display.ch;

            uint64_t wmarmark_len = wmarBufInfo.property.info.picture.display.len;
            uint64_t _len = watermark_w * watermark_h * wmatermark_channel;
            if (wmarmark_len != _len)
            {
                ALOGV("%s %d : error wmarmark_len != _len", __func__, __LINE__);
                return -1;
            }

            ALOGV("%s ->", __func__);
            if (!bufptr)
            {
                ALOGE("%s %d: error bufptr==NULL", __func__, __LINE__);
                return -1;
            }

            int displayOffset = displayX + displayY * rawWidth;
            if (displayOffset >= (rawWidth * (rawHeight - watermark_h)))
            {
                displayOffset = 0;
            }
            for (int h = 0; h < watermark_h; h++)
            {
                for (int w = 0; w < watermark_w; w++)
                {
                    int index = h * rawWidth * channel + w * channel + displayOffset * channel;
                    unsigned char *b = &bufptr[index + 0];
                    unsigned char *g = &bufptr[index + 1];
                    unsigned char *r = &bufptr[index + 2];
                    unsigned char *a = &bufptr[index + 3];

                    uint8_t *tmpBuf = &buf[h * watermark_w * wmatermark_channel + w * wmatermark_channel];
                    if (*tmpBuf != 0)
                    {
                        *b = 255;
                        *g = 255;
                        *r = 255;
                        ALOGV("%s %d ; != 0", __func__, __LINE__);
                    }
                    else
                    {
                        ALOGV("%s %d ; == 0", __func__, __LINE__);

                        // a:0 表示透明，  a:1 表示非透明
                        if (!wmarBufInfo.property.info.picture.display.bg.a)
                        {
                            int _b = *b - wmarBufInfo.property.info.picture.display.bg.b;
                            int _g = *g - wmarBufInfo.property.info.picture.display.bg.g;
                            int _r = *r - wmarBufInfo.property.info.picture.display.bg.r;
                            if (_b > 200 || _b < 0)
                            {
                                _b = *b;
                            }

                            if (_g > 200 || _g < 0)
                            {
                                _g = *g;
                            }

                            if (_r > 200 || _r < 0)
                            {
                                _r = *r;
                            }
                            *b = (unsigned char)_b;
                            *g = (unsigned char)_g;
                            *r = (unsigned char)_r;
                        } else {
                            *b = wmarBufInfo.property.info.picture.display.bg.b;
                            *g = wmarBufInfo.property.info.picture.display.bg.g;
                            *r = wmarBufInfo.property.info.picture.display.bg.r;
                        }
                    }
                }
            }

            ALOGV("%s <-", __func__);
            return 0;
        }

        int WmarkBufManager::handlePng(algorithm_info_t &info, WmarkBuf &wmarBufInfo)
        {
            unsigned char *bufptr = info.bufptr;
            int size = info.size;
            int rawWidth = info.rawWidth;
            int rawHeight = info.rawHeight;
            int channel = size / (rawWidth * rawHeight);
            int displayX = -1, displayY = -1;
            int watermark_h = -1, watermark_w = -1, wmatermark_channel = -1;
            uint8_t *buf = wmarBufInfo.buf;

            if (!buf || wmarBufInfo.property.info.picture.display.len > wmarBufInfo.bufMaxLen)
            {
                ALOGE("%s %d : error", __func__, __LINE__);
                return -1;
            }

            displayX = wmarBufInfo.property.info.picture.display.x;
            displayY = wmarBufInfo.property.info.picture.display.y;
            watermark_w = wmarBufInfo.property.info.picture.display.w;
            watermark_h = wmarBufInfo.property.info.picture.display.h;
            wmatermark_channel = wmarBufInfo.property.info.picture.display.ch;

            uint64_t wmarmark_len = wmarBufInfo.property.info.picture.display.len;
            uint64_t _len = watermark_w * watermark_h * wmatermark_channel;

            if (wmarmark_len != _len)
            {
                ALOGE("%s %d : error wmarmark_len != _len", __func__, __LINE__);
                return -1;
            }

            ALOGV("%s ->", __func__);
            if (!bufptr)
            {
                ALOGE("WMarkAlgorithm::%s error bufptr==NULL", __func__);
                return -1;
            }

            int displayOffset = displayX + displayY * rawWidth;
            if (displayOffset >= (rawWidth * (rawHeight - watermark_h)))
            {
                displayOffset = 0;
            }

            for (int h = 0; h < watermark_h; h++)
            {
                for (int w = 0; w < watermark_w; w++)
                {
                    uint8_t *tmp = &buf[h * watermark_w * wmatermark_channel + w * wmatermark_channel];
                    if (tmp[0] != 0)
                    {
                        int index = h * rawWidth * channel + w * channel + displayOffset * channel;
                        unsigned char *b = &bufptr[index + 0];
                        unsigned char *g = &bufptr[index + 1];
                        unsigned char *r = &bufptr[index + 2];
                        unsigned char *a = &bufptr[index + 3];

                        *r = tmp[1];
                        *g = tmp[2];
                        *b = tmp[3];
                    }
                }
            }
            ALOGV("%s <-", __func__);
            return 0;
        }

    } // algorithm
} // camera
